#!/bin/bash
# Copyright (c) 2024 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import sys
import shutil
import argparse
import json
import stat
import traceback


def update_record(replace_record, part_name, indep_so_path, destination):
    if part_name not in replace_record:
        replace_record[part_name] = dict()
    if indep_so_path not in replace_record[part_name]:
        replace_record[part_name][indep_so_path] = list()
    replace_record[part_name][indep_so_path].append(destination)


def save_record(part_name, replace_record):
    code_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    record_json_file = os.path.join(code_path, "replace_record", part_name, "replace.json")
    if os.path.exists(record_json_file):
        os.remove(record_json_file)
    with open(record_json_file, 'w', encoding='utf-8') as f:
        json.dump(replace_record, f, indent=4)


def create_so_back_dir(part_name):
    code_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    indep_so_back_dir = os.path.join(code_path, "replace_record", part_name, "indep")
    rk_so_back_dir = os.path.join(code_path, "replace_record", part_name, "rk3568")
    if os.path.exists(indep_so_back_dir):
        shutil.rmtree(indep_so_back_dir)
    os.makedirs(indep_so_back_dir, exist_ok=True)
    if os.path.exists(rk_so_back_dir):
        shutil.rmtree(rk_so_back_dir)
    os.makedirs(rk_so_back_dir, exist_ok=True)
    return indep_so_back_dir, rk_so_back_dir


def backup_component_sofile(indep_so_path, rk_so_path, indep_so_back_dir, rk_so_back_dir, is_file=True):
    if is_file:
        if os.path.exists(indep_so_path):
            shutil.copy(indep_so_path, indep_so_back_dir)
        if os.path.exists(rk_so_path):
            shutil.copy(rk_so_path, rk_so_back_dir)
    else:
        if os.path.exists(indep_so_path):
            dir_name = os.path.basename(indep_so_path)
            dst_dir = os.path.join(indep_so_back_dir, dir_name)
            shutil.copytree(indep_so_path, dst_dir)
        if os.path.exists(rk_so_path):
            dir_name = os.path.basename(rk_so_path)
            dst_dir = os.path.join(rk_so_back_dir, dir_name)
            shutil.copytree(rk_so_path, dst_dir)

    
def copy_component_sofile(_source_list, part_name, old_folder, new_folder, variant):
    indep_so_back_dir, rk_so_back_dir = create_so_back_dir(part_name)
    replace_record = dict()
    for source_info in _source_list:
        so_path_list = source_info.get("dest")
        so_path = source_info.get("source")
        indep_so_path = os.path.join(new_folder, 'out', variant, "src", so_path)
        for dst in so_path_list:
            rk_so_path = os.path.join(old_folder, 'out', 'rk3568', 'packages', 'phone', dst)
            if not os.path.exists(indep_so_path):
                continue
            if os.path.isfile(indep_so_path):
                backup_component_sofile(indep_so_path, rk_so_path, indep_so_back_dir, rk_so_back_dir)
                shutil.copy(indep_so_path, rk_so_path)
                update_record(replace_record, part_name, indep_so_path, rk_so_path)
                print(f'{part_name}:{dst} done')
            elif os.path.isdir(indep_so_path):
                backup_component_sofile(indep_so_path, rk_so_path, indep_so_back_dir, rk_so_back_dir, is_file=False)
                print(f"copy dir {indep_so_path} to {rk_so_path}")
                shutil.rmtree(rk_so_path)
                shutil.copytree(indep_so_path, rk_so_path)
                update_record(replace_record, part_name, indep_so_path, rk_so_path)
                print(f'{part_name}:{dst} done')
    save_record(part_name, replace_record)

def load_json(file_path):
    with os.fdopen(os.open(file_path, os.O_RDWR | os.O_CREAT, stat.S_IWUSR | stat.S_IRUSR), 'r', encoding='utf-8') as f:
        try:
            return json.load(f)
        except json.JSONDecodeError as e:
            print(f"Error decoding JSON: {e}")
            return None

def _get_system_module_info(folder, part_name):
    """
    try to get sytem module info from out/rk3568/packages/phone/system_module_info.json 
    """
    _part_system_module_path = os.path.join(folder, 'out', 'rk3568', 'packages', 'phone', 'system_module_info.json')
    try:
        if not os.path.exists(_part_system_module_path):
            print(f"system_module_info.json not found: {_part_system_module_path}")
            return []
        if os.path.getsize(_part_system_module_path) == 0:
            print(f"File is empty: {_part_system_module_path}")
            return []
        jsondata = load_json(_part_system_module_path)
        if jsondata is not None:
            return [item for item in jsondata if item.get("part_name") == part_name]
    except Exception as e:
        print(f"Unexpected error: {e}")
    return []


def _get_components_json(out_path):
    jsondata = ""
    json_path = os.path.join(out_path + "/build_configs/parts_info/components.json")
    with os.fdopen(os.open(json_path, os.O_RDWR | os.O_CREAT, stat.S_IWUSR | stat.S_IRUSR),
            'r', encoding='utf-8') as f:
        try:
            jsondata = json.load(f)
        except Exception as e:
            print('--_get_components_json parse json error--')
    return jsondata
    
    
def _get_parts_path_info(components_json):
    jsondata = dict()
    try:
        for component, v in components_json.items():
            jsondata[component] = v.get('path')
    except Exception as e:
        print('--_get_part_subsystem parse json error--')
    return jsondata
    
    
def _get_parts_path(json_data, part_name):
    parts_path = None
    if json_data.get(part_name) is not None:
        parts_path = json_data[part_name]
    return parts_path


def main():
    parser = argparse.ArgumentParser()
    # parser.add_argument('--subsystem-name')
    parser.add_argument('--part-name')
    parser.add_argument('--new-folder')
    parser.add_argument('--old-folder')
    parser.add_argument('--variant')
    args = parser.parse_args()

    print(args)

    # subsystem_name = args.subsystem_name
    part_name = args.part_name
    variant = args.variant
    old_folder = args.old_folder
    new_folder = args.new_folder
    components_json = _get_components_json(os.path.join(old_folder, 'out', 'rk3568'))
    parts_path_info = _get_parts_path_info(components_json)
    part_path = _get_parts_path(parts_path_info, part_name)
    _source_list = _get_system_module_info(old_folder, part_name)
    copy_component_sofile(_source_list, part_name, old_folder, new_folder, variant)


if __name__ == '__main__':
    main()